package com.atguigu.tingshu.common.login;

import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import jakarta.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @BelongsProject: tingshu-parent
 * @BelongsPackage: com.atguigu.tingshu.common.login
 * @Author: jiangyi
 * @CreateTime: 2025-09-29  18:41
 * @Description: TODO
 * @Version: 1.0
 */
@Component
@Aspect
public class GuiGuLoginAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @SneakyThrows // 动态生成try catch(Throwable)
    @Around("execution(* com.atguigu.tingshu.*.api.*.*(..)) && @annotation(guiGuLogin)")
    public Object loginAspect(ProceedingJoinPoint joinPoint, GuiGuLogin guiGuLogin){

        Object resultObject = new Object();
        // 1.RequestContextHolder上下文管理工具类 可在任何位置获取当前请求
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        //1.4 基于请求对象获取请求头：token
        String token = request.getHeader("token");

        //2.查询存放在Redis中用户信息（何时存入：登录成功后）
        //2.1 构建用户登录信息key
        String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
        //2.2 查询存入Redis中用户信息
        UserInfoVo UserInfoVo = (UserInfoVo) redisTemplate.opsForValue().get(loginKey);

        //3.判断注解是否要求必须登录，如果要求登录且用户信息为空，抛出异常业务状态：
        // 208引导用户登录
        if (guiGuLogin.required() && UserInfoVo == null) {
            throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
        }

        //4.如果用户信息存在，将用户ID存入ThreadLocal
        if (UserInfoVo != null) {
            AuthContextHolder.setUserId(UserInfoVo.getId());
        }

        //二、执行目标方法
        resultObject = joinPoint.proceed();


        //5.将ThreaLocal中数据手动清理避免OOM出现 tomcat只有150个线程
        AuthContextHolder.removeUserId();

        return resultObject;


    }
}
